package com.tplhk.app.payment.service.impl;


import com.tplhk.app.payment.constants.PaymentProcessConstants;
import com.tplhk.app.payment.model.entity.PaymentProcessInfoEntity;
import com.tplhk.app.payment.model.param.PaymentConfirmParam;
import com.tplhk.app.payment.model.param.PaymentRequestParam;
import com.tplhk.app.payment.model.wrapper.PaymentProcessVariablesWrapper;
import com.tplhk.app.payment.service.IBizPaymentProcessInfoService;
import com.tplhk.camunda.starter.model.param.process.ProcessVariablesQueryParam;
import com.tplhk.camunda.starter.model.param.process.TaskQueryParam;
import com.tplhk.camunda.starter.model.vo.TaskVo;
import com.tplhk.camunda.starter.model.vo.TwoTuple;
import com.tplhk.camunda.starter.servcie.CamundaCommonService;
import com.tplhk.camunda.starter.util.CamundaUtils;
import lombok.extern.slf4j.Slf4j;
import org.camunda.bpm.engine.history.HistoricTaskInstance;
import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

/**
 * 支付流程 - 业务数据 服务实现类
 *
 * @author jqxu
 * @since 2022-05-30
 */
@Service
@Slf4j
public class BizPaymentProcessInfoServiceImpl implements IBizPaymentProcessInfoService {

    @Resource
    private CamundaCommonService camundaCommonService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String startPaymentProcess(PaymentRequestParam paymentRequestParam) {
        /** 插入支付流程业务数据 */
        PaymentProcessInfoEntity paymentProcessInfoEntity = new PaymentProcessInfoEntity();
        //拷贝参数中的属性：productName, productPrice, paymentAssignee
        BeanUtils.copyProperties(paymentRequestParam, paymentProcessInfoEntity);
        log.info("保存支付流程业务数据到数据库，入库操作省略，参数：{}", paymentRequestParam);
        // todo save(paymentProcessInfoEntity);
        paymentProcessInfoEntity.setId(String.valueOf(System.currentTimeMillis()));
        /** 启动支付流程 */
        log.info("开启支付流程处理，processKey：{}, businessKey：{}", PaymentProcessConstants.PAYMENT_PROCESS_ID, paymentProcessInfoEntity.getId());
        ProcessInstance processInstance = this.camundaCommonService.startProcessInstance(
                PaymentProcessConstants.PAYMENT_PROCESS_ID,
                String.valueOf(paymentProcessInfoEntity.getId()),
                paymentRequestParam);
        log.info("开启支付流程处理，结果：id = {}, getProcessInstanceId = {}, getProcessDefinitionId = {}, getBusinessKey = {}",
                processInstance.getId(),
                processInstance.getProcessInstanceId(),
                processInstance.getProcessDefinitionId(),
                processInstance.getBusinessKey());

        /** 更新业务数据中的流程实例ID */
        paymentProcessInfoEntity.setProcessInstanceId(processInstance.getId());
        // todo update(paymentProcessInfoEntity);

        return paymentProcessInfoEntity.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String confirmPayment(PaymentConfirmParam paymentConfirmParam) {
        String taskId = camundaCommonService.getTaskId(paymentConfirmParam.getProcessInstanceId(), paymentConfirmParam.getTaskId());
        if(null == taskId){
            log.error("找不到 taskId, 参数：{}, taskId: {}", paymentConfirmParam, taskId);
            return null;
        }
        paymentConfirmParam.setTaskId(taskId);
        log.info("用户确认支付, 参数：{}", paymentConfirmParam);

        /** 查询当前流程实例已经存在的流程变量 */
        ProcessVariablesQueryParam processVariablesQueryParam = ProcessVariablesQueryParam.builder()
                //.taskId(paymentConfirmParam.getTaskId())
                .processInstanceId(paymentConfirmParam.getProcessInstanceId())
                .build();
        Map<String, Object> existProcessVariables = this.camundaCommonService.getRuntimeProcessVariables(processVariablesQueryParam);
        log.info("获取当前已存在流程变量，结果：{}", existProcessVariables);
        //使用流程变量包装器（便于获取属性）
        PaymentProcessVariablesWrapper existPaymentProcessVariablesWrapper = new PaymentProcessVariablesWrapper(existProcessVariables);

        /** 更新业务流程数据（更新范围：之前流程添加的 + 当前操作添加的 流程变量 ） */
        PaymentProcessInfoEntity bizPaymentProcessInfo = PaymentProcessInfoEntity.builder()
                .productDiscount(existPaymentProcessVariablesWrapper.getProductDiscount())
                .productDiscountPrice(existPaymentProcessVariablesWrapper.getProductDiscountPrice())
                .approvalResult(paymentConfirmParam.getApprovalResult())
                .approvalTime(LocalDateTime.now())
                .id(paymentConfirmParam.getBizKey())
                .build();
        log.info("更新用户确认信息，参数：{}", bizPaymentProcessInfo);
        // todo 更新业务表： 折扣价格，是否同意等信息
//        Boolean result = this.updateById(bizPaymentProcessInfo);

        /** 更新流程引擎（完成用户确认任务 + 添加新的流程变量（用于后续网关判断）） */
        Map<String, Integer> processVariables = CamundaUtils.convertProcessVariablesFromPair(PaymentProcessConstants.PAYMENT_APPROVAL_RESULT_VAR_NAME, paymentConfirmParam.getApprovalResult());
        this.camundaCommonService.completeTask(paymentConfirmParam.getTaskId(), processVariables);

        return paymentConfirmParam.getTaskId();
    }

    @Override
    public TwoTuple<List<TaskVo<PaymentProcessInfoEntity>>, Long> queryTasks(TaskQueryParam taskQueryParam) {
//        Consumer<TaskQuery> extendTaskQuery = (x) -> {
//            // 这里设置额外的查询条件
//            x.caseDefinitionKey("kkkkkkkk");
//            x.caseDefinitionId("2eeeeee");
//        };
        TwoTuple<List<TaskVo<PaymentProcessInfoEntity>>, Long> twoTuple = this.camundaCommonService.queryRuntimeTasks(
                taskQueryParam,
                null,
                taskQueryParam.getTaskBizKeyVariableName(),
                (productName) -> {
                    // todo 根据 productName 值查询业务数据，存到 setTaskVoTaskData
                    log.info("productName::::::{}", productName);
        //            return this.getById(Long.valueOf(bizKey));
                    return new PaymentProcessInfoEntity();
                },
                (bizKey) -> {
                    // todo 根据 BusinessKey 返回业务数据
                    log.info("BusinessKey::::::{}", bizKey);
        //            return this.getById(Long.valueOf(bizKey));
                    return new PaymentProcessInfoEntity();
                });
        log.info("查询待处理任务列表，结果：{}", twoTuple.getFirst());

        return twoTuple;
    }


    @Override
    public TwoTuple<List<HistoricTaskInstance>, Long> queryHistoryTasks(TaskQueryParam taskQueryParam) {
        return this.camundaCommonService.queryHistoryTasks(taskQueryParam);
    }

}
